/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! CHECKER             Ecma builtins inlining. Speculations should be the following: (INTEGER + Intrinsic) --deopt--> (DOUBLE/INT + Intrinsic).
//! RUN                 options: "--compiler-regex=\"_GLOBAL::profiling_(clz32|sin)\"", entry: "_GLOBAL::func_main_0"
//! METHOD              "profiling_sin"
//! EVENT               /Compilation.*profiling_sin.*COMPILED/
//! PASS_AFTER          "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT           "LoadImmediate"
//! INST_NEXT           "LoadObject"
//! INST_NEXT           "Compare NE"
//! INST_NEXT           "DeoptimizeIf INLINE_DYN"
//! INST_NEXT           "AnyTypeCheck ECMASCRIPT_INT_TYPE"
//! INST_NEXT           "CastAnyTypeValue ECMASCRIPT_INT_TYPE"
//! INST_NEXT           "Cast "
//! INST_NEXT           "Intrinsic.MathSinF64"
//! EVENT_NEXT          /DeoptimizationReason,.*profiling_sin.*,NOT_SMALL_INT/
//! EVENT_NEXT          /Compilation.*profiling_sin.*COMPILED/
//! PASS_AFTER_NEXT     "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT           "LoadImmediate"
//! INST_NEXT           "LoadObject"
//! INST_NEXT           "Compare NE"
//! INST_NEXT           "DeoptimizeIf INLINE_DYN"
//! INST_NEXT           "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT           "CastAnyTypeValue ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT           "Intrinsic.MathSinF64"
//! EVENT_NEXT_NOT      /Deoptimization.*profiling_sin/
//! EVENT_NEXT_NOT      /Compilation.*profiling_sin/

//! CHECKER             Ecma builtins inlining. Check for intrinsics that accepts only ECMASCRIPT_INT_TYPE. Speculations should be the following: (INTEGER + Intrinsic) --deopt--> (CallDynamic).
//! RUN                 options: "--compiler-regex=\"_GLOBAL::profiling_(clz32|sin)\"", entry: "_GLOBAL::func_main_0"
//! METHOD              "profiling_clz32"
//! EVENT               /Compilation.*profiling_clz32.*COMPILED/
//! PASS_AFTER          "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT           "LoadImmediate"
//! INST_NEXT           "LoadObject"
//! INST_NEXT           "Compare NE"
//! INST_NEXT           "DeoptimizeIf INLINE_DYN"
//! INST_NEXT           "AnyTypeCheck ECMASCRIPT_INT_TYPE"
//! INST_NEXT           "CastAnyTypeValue ECMASCRIPT_INT_TYPE"
//! INST_NEXT_NOT       "Cast "
//! INST_NEXT           "Intrinsic.StdMathClz32"
//! EVENT_NEXT          /DeoptimizationReason,.*profiling_clz32.*,NOT_SMALL_INT/
//! EVENT_NEXT          /Compilation.*profiling_clz32.*COMPILED/
//! PASS_AFTER_NEXT     "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT_NOT       "LoadImmediate"
//! INST_NEXT_NOT       "LoadObject"
//! INST_NEXT_NOT       "Compare NE"
//! INST_NEXT_NOT       "DeoptimizeIf INLINE_DYN"
//! INST_NEXT           "CallDynamic"
//! EVENT_NEXT_NOT      /Deoptimization.*profiling_clz32/
//! EVENT_NEXT_NOT      /Compilation.*profiling_clz32/

function profiling_sin(arg)
{
    let saved_arg = arg;
    // Increment is necessary to profile the type:
    let res = Math.sin(arg++);
    arg = saved_arg;
    return res;
}

function profiling_clz32(arg)
{
    let saved_arg = arg;
    // Increment is necessary to profile the type.
    // clz32 is inlined only for integers
    let res = Math.clz32(arg++);
    arg = saved_arg;
    return res;
}

function check(arg)
{
    let lhs;
    let rhs;

    lhs = Math.sin(arg);
    rhs = profiling_sin(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }

    lhs = Math.clz32(arg);
    rhs = profiling_clz32(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }

    RuntimeTesting.OptimizeFunctionOnNextCall(profiling_sin);
    RuntimeTesting.OptimizeFunctionOnNextCall(profiling_clz32);

    lhs = Math.sin(arg);
    rhs = profiling_sin(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }

    lhs = Math.clz32(arg);
    rhs = profiling_clz32(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }
};

RuntimeTesting.PrepareFunctionForOptimization(profiling_sin);
RuntimeTesting.PrepareFunctionForOptimization(profiling_clz32);

// Profile as integer:
check(3);
// Deopt, profile as double with int
check(3.1);
// No deoptimization
check(3);
check(3.1);
check(3);
check(3.1);
